home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: ls.c
- *
- * Unix-like directory listing program for OS/2
- *
- * Bob Eager April 1991
- *
- */
-
- /*
- * History:
- * 1.0 - Initial version
- * 1.1 - Corrected filename sort for HPFS volumes.
- * 1.2 - Replaced 'isatty' call with local version since MSC one
- * is broken in version 6.0 (won't differentiate devices).
- *
- */
-
- /* Program version information */
-
- #define VERSION 1
- #define EDIT 1
-
- #include <sys\types.h>
- #include <conio.h>
- #include <ctype.h>
- #include <direct.h>
- #include <errno.h>
- #include <search.h>
- #include <sys\stat.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
-
- #define INCL_DOSDATETIME
- #define INCL_DOSFILEMGR
- #include <os2.h>
-
- #define FSQBUFSIZE 100 /* Size of FS query buffer */
- #define MAXFILE 500 /* Max files per directory */
- #define SCRSIZ 22 /* Scrolling size of display screen */
- #define SCRWID 75 /* Column width of display screen */
-
- /* Type definitions */
-
- enum fs_t {
- FS_FAT, /* DOS-type (FAT) file system */
- FS_HPFS /* High Performance file system */
- };
- enum tm_t {
- TIME_MOD, /* Sort on time modified */
- TIME_ACC, /* Sort on time accessed */
- TIME_CRE /* Sort on time created */
- };
-
- /* Format of output buffer -- array of file structs */
-
- static struct outbuf {
- USHORT oattr; /* Attributes */
- FDATE odate; /* File date */
- FTIME otime; /* File time */
- ULONG osize; /* File size (logical) */
- ULONG oasize; /* File size (allocated) */
- ULONG easize; /* Size of extended attributes */
- CHAR *oname; /* File name */
- } *obuf;
-
- /* Forward references */
-
- static int comp(struct outbuf *, struct outbuf *);
- static void curdrv(CHAR *);
- static CHAR endlin(void);
- static void fill(int, struct llst *);
- static enum fs_t fstype(CHAR *);
- static int gcdate(void);
- static ULONG getleft(CHAR *, int *);
- static void longlist(int);
- static char *mname(int);
- static BOOL my_isatty(int);
- static void putusage(void);
- static void search(CHAR *);
- static void shortlist(int);
-
- /* Help text */
-
- static const char *helpinfo[] = {
- "%s: list contents of directory\n",
- "Synopsis: %s [options] file ...",
- " Options:",
- " -a list all files, including hidden and directory",
- " -c sort by date and time created instead of by name (HPFS only)",
- " -d output details of directory rather than its contents",
- " -e output size of extended attributes rather than of file",
- " -h display this help",
- " -i display file system type",
- " -l long listing (attributes, sizes, dates etc.)",
- " -r reverse direction of sort",
- " -s output allocated size of each file",
- " -t sort by date and time modified instead of by name",
- " -u sort by date and time last accessed instead of by name (HPFS only)",
- " -R recursively list subdirectories",
- " -1 single column output",
- ""
- };
-
- /* Format of long listing buffer */
-
- struct llst { /* Structure to hold file information*/
- CHAR fattr[7]; /* File attribute string */
- ULONG size; /* File size */
- int day; /* The day of creation */
- int mnum; /* Month number */
- int yr; /* Year */
- int hh; /* Creation times */
- int mm;
- int ap; /* am or pm */
- };
-
- /* Global variables and flags */
-
- static BOOL all = 0; /* -a: Include hidden & system files */
- static BOOL ll = 0; /* -l: Long listing */
- static BOOL col1 = 0; /* -1: 1-column format */
- static BOOL direct = 0; /* -d: Output directory details */
- static BOOL eas = 0; /* -e: Output size of EAs */
- static BOOL fsinfo = 0; /* -i: Output file system info */
- static BOOL recd = 0; /* -R: Recursive descent requested */
- static BOOL rev = 0; /* -r: Reverse sort */
- static BOOL tsrt = 0; /* -t: Sort the listing by time */
- static BOOL usage = 0; /* -u: Output disk usage */
-
- static enum tm_t timetype = TIME_MOD; /* Type of time for sort */
- static enum fs_t fs; /* File system type */
- static int np = 0; /* Number of groups printed */
- static int nargs; /* Number of non-option arguments */
- static int drive; /* Code number for drive requested */
- static CHAR *progname; /* Program name */
- static BOOL tsc; /* TRUE iff output is to console */
- static ULONG total; /* Total of sizes encountered */
- static int lc = 0; /* Line counter */
- static CHAR spath[_MAX_PATH+2]; /* Holds current drv/pathname string */
-
-
- /*
- * Main entry point
- *
- */
-
- void main(int argc, CHAR *argv[])
- { CHAR *s;
-
- progname = argv[0];
-
- /* Process input options */
-
- while(--argc > 0 && (*++argv)[0] == '-') {
- for(s = argv[0]+1; *s != '\0'; s++) {
- switch(*s) {
- case 'a': /* -a: list all files */
- all++;
- break;
-
- case 'c': /* -c: creation time sort */
- tsrt++;
- timetype = TIME_CRE;
- break;
-
- case 'd': /* -d: directory details */
- direct++;
- break;
-
- case 'e': /* -e: EA sizes */
- eas++;
- break;
-
- case 'h': /* -h: print help */
- putusage();
- exit(EXIT_SUCCESS);
-
- case 'i': /* -i: file system info */
- fsinfo++;
- break;
-
- case 'l': /* -l: long listing */
- ll++;
- break;
-
- case 'r': /* -r: reverse sort direction */
- rev++;
- break;
-
- case 's': /* -s: disk usage */
- usage++;
- break;
-
- case 't': /* -t: modification time sort */
- tsrt++;
- timetype = TIME_MOD;
- break;
-
- case 'u': /* -u: access time sort */
- tsrt++;
- timetype = TIME_ACC;
- break;
-
- case 'R': /* -R: recursive list */
- recd++;
- break;
-
- case '1': /* -1: 1-column listing */
- col1++;
- break;
-
- default:
- fprintf(stderr,
- "%s: invalid flag -%c\n", progname, *s);
- exit(EXIT_FAILURE);
- }
- }
- }
-
- if(direct) usage = recd = 0;
-
- nargs = argc;
- tsc = my_isatty(fileno(stdout));
- /* See if output to screen */
-
- obuf = (struct outbuf *) malloc(sizeof(*obuf)*MAXFILE);
- if(obuf == (struct outbuf *) NULL) {
- fprintf(stderr, "%s: not enough memory\n", progname);
- exit(EXIT_FAILURE);
- }
-
- if(argc == 0) { /* Default to current drive */
- argc++;
- curdrv(spath);
- } else (void) strcpy(spath, *argv);
-
- /* Cycle through args present */
-
- for(;;) {
- if(spath[1] == ':' && spath[2] == '\0') {
- /* If drive only */
- (void) _getdcwd(spath[0]-'a'+1, spath, _MAX_PATH);
- }
-
- fs = fstype(spath); /* See if FAT or HPFS file system */
-
- search(spath); /* Do the actual listing */
-
- if(--argc != 0) {
- (void) strcpy(spath, *++argv);
- } else {
- if(usage) {
- ULONG left = getleft(spath, &drive);
-
- if(np > 1) {
- fprintf(stdout,
- "---------\n%9ld bytes total; ",
- total);
- }
- fprintf(stdout,
- "%9ld bytes left on drive %c:\n", left,
- drive + 'a' - 1);
- }
- break;
- }
- }
- free(obuf);
-
- exit(EXIT_SUCCESS);
- }
-
-
- /*
- * Search 'path' for filename or directory
- *
- */
-
- static void search(CHAR *path)
- { USHORT mask = FILE_DIRECTORY; /* Attribute mask */
- char *work; /* Working path string */
- int path_len; /* Length of initial path */
- USHORT res; /* Return code from find calls */
- HDIR hd; /* Directory handle */
- FILEFINDBUF2 *fb; /* Buffer for file information */
- USHORT count; /* Count of files found */
- int k = 0; /* Counts number of entries found */
- CHAR ch; /* Temporary */
- CHAR *name; /* Temporary */
- ULONG bytes = 0; /* Count of disk usage this directory*/
- enum tm_t tt = timetype; /* Type of time output/sort */
- int nargs; /* Number of files or directories */
-
- work = (char *) malloc(CCHMAXPATH);
- fb = (FILEFINDBUF2 *) malloc(sizeof(FILEFINDBUF2));
-
- if(fs == FS_FAT) tt = TIME_MOD; /* Does not keep other times */
-
- if(all) mask = FILE_DIRECTORY | FILE_SYSTEM |
- FILE_HIDDEN | FILE_READONLY | FILE_NORMAL;
-
- (void) strcpy(work, path);
- path_len = strlen(work); /* Save original path length */
- hd = HDIR_CREATE; /* Create new directory handle */
- count = 1; /* Get information about one file */
-
- if(fs == FS_FAT) (void) strlwr(work);
-
- /* Handle the case where the argument refers to a directory, either
- explicitly (it ends in the path separator) or implicitly (it turns
- out to be a directory). Concatenate a full wildcard specification
- to get everything in the directory, unless the '-d' flag was
- specified. */
-
- if(!direct) {
- res = DosFindFirst2(work, &hd, FILE_NORMAL, fb,
- sizeof(FILEFINDBUF2), &count,
- FIL_QUERYEASIZE, (ULONG) 0);
- if(res != 0) count = 0;
-
- if(count == 0 || work[path_len-1] == '\\') {
- if(work[path_len-1] != '\\') {
- (void) strcat(work, "\\");
- /* If path is to a directory */
- path_len++;
- }
- (void) strcat(work, "*.*");
- /* List everything in it */
- }
- (void) DosFindClose(hd);
- }
-
- /* Main loop to scan all normal files in the directory, and store
- details of them. */
-
- hd = HDIR_CREATE; /* Create new directory handle */
- count = 1; /* Get information about one file */
- res = DosFindFirst2(work, &hd, mask, fb, sizeof(FILEFINDBUF2),
- &count, FIL_QUERYEASIZE, (ULONG) 0);
- if(res != 0) count = 0;
-
- if(count != 0) {
- do {
- /* Ignore "." and ".." unless -a option */
-
- if(!(fb->achName[0] == '.' && !all)) {
-
- /* Store this entry */
-
- obuf[k].oattr = fb->attrFile;
- obuf[k].osize = fb->cbFile;
- obuf[k].oasize = fb->cbFileAlloc;
- if(fb->cbList == sizeof(ULONG))
- fb->cbList = 0; /* No real EAs */
- obuf[k].easize = fb->cbList;
-
- switch(tt) {
- case TIME_MOD:
- obuf[k].otime = fb->ftimeLastWrite;
- obuf[k].odate = fb->fdateLastWrite;
- break;
-
- case TIME_ACC:
- obuf[k].otime = fb->ftimeLastAccess;
- obuf[k].odate = fb->fdateLastAccess;
- break;
-
- case TIME_CRE:
- obuf[k].otime = fb->ftimeCreation;
- obuf[k].odate = fb->fdateCreation;
- }
-
- name = (CHAR *) malloc(sizeof(fb->achName)+2);
- /* Extra byte for possible \ */
- (void) strcpy(name, fb->achName);
- obuf[k].oname = name;
-
- if(usage) {
- ULONG add = fb->cbFileAlloc;
-
- if((fb->attrFile & FILE_DIRECTORY) &&
- fb->achName[0] != '.') {
- bytes += add;
- } else { /* Sum up disk usage */
- bytes += add;
- }
- }
- if(++k >= MAXFILE) {
- fprintf(stderr,
- "%s: more than %d files in directory\n",
- progname, MAXFILE);
- }
- }
- count = 1;
- if(DosFindNext(hd, (FILEFINDBUF *) fb,
- sizeof(FILEFINDBUF2), &count) != 0) count = 0;
- } while(count != 0);
- (void) DosFindClose(hd);
- } else {
- work[path_len-1] = '\0';
- fprintf(stderr,
- "%s: can't find a file or directory named \"%s\"\n",
- progname, work);
- (void) DosFindClose(hd);
- free(work);
- }
-
- work[path_len] = '\0'; /* Restore directory pathname */
-
- ch = endlin();
- if(np++) putchar(ch); /* Separate listing blocks */
-
- if(usage) {
- total += bytes; /* Total bytes to date */
- fprintf(stdout, "%9ld ", bytes);
- }
-
- /* Identify the block */
-
- fprintf(stdout, "%s", work);
- if(fsinfo)
- fprintf(stdout, " (%s)", fs == FS_FAT ? "FAT" : "HPFS");
- ch = endlin();
- fputc(ch, stdout);
-
- /* Sort the entries and print them */
-
- qsort(obuf, k, sizeof(obuf[0]), comp);
- if(ll) longlist(k); else shortlist(k);
-
- /* Free the space allocated for file names */
-
- while(--k >= 0) free(obuf[k].oname);
-
- if(!recd) { /* Quit if not -R */
- free(work);
- return;
- }
-
- (void) strcat(work, "*.*");
- hd = HDIR_CREATE; /* Create new directory handle */
- count = 1;
- res = DosFindFirst2(work, &hd, mask, fb, sizeof(FILEFINDBUF2), &count,
- FIL_QUERYEASIZE, (ULONG) 0);
-
- if(count != 0) { /* Else find all sub-dirs */
- do {
- if(fb->attrFile & FILE_DIRECTORY &&
- fb->achName[0] != '.') {
- work[path_len] = 0;
- /* Discard old name */
- if(fs == FS_FAT)
- (void) strlwr(fb->achName);
- (void) strcat(work, fb->achName);
- /* Install a new one */
- (void) strcat(work, "\\");
- search(work);
- /* And recurse */
- }
- count = 1;
- if(DosFindNext(hd, (FILEFINDBUF *) fb,
- sizeof(FILEFINDBUF2), &count) != 0) count = 0;
- } while(count != 0);
- }
- (void) DosFindClose(hd);
-
- free(work);
- }
-
-
- /*
- * Get current default drive
- *
- */
-
- static void curdrv(CHAR *sp)
- { int drive = _getdrive();
-
- *sp++ = (CHAR) (drive + 'a' - 1);
- *sp++ = ':';
- *sp = '\0';
- }
-
-
- /*
- * Get space left on requested drive
- *
- */
-
- static ULONG getleft(CHAR *pp, int *drv)
- { ULONG cs;
- FSALLOCATE fsall;
- int drive;
-
- if(*(pp+1) == ':') { /* Use specified drive if any */
- drive = tolower(*pp) - 'a' + 1;
- } else {
- drive = _getdrive();
- }
- *drv = drive;
-
- (void) DosQFSInfo(drive, 1, (PBYTE) &fsall, sizeof(fsall));
- cs = fsall.cSectorUnit * fsall.cbSector; /* Bytes/cluster */
-
- return(cs * fsall.cUnitAvail); /* # of unused clusters */
- }
-
-
- /*
- * Return a file date in normalised form
- *
- */
-
- static ULONG ndate(FDATE n)
- { return(n.year*12L + n.month)*31L + n.day;
- }
-
-
- /*
- * Return a file time in normalised form
- *
- */
-
- static ULONG ntime(FTIME n)
- { return((n.hours*60L + n.minutes)*30L + n.twosecs);
- }
-
-
- /*
- * Compare two entries
- *
- */
-
- static int comp(struct outbuf *a, struct outbuf *b)
- { int y;
-
- if(tsrt) {
- if(ndate(a->odate) != ndate(b->odate)) {
- /* If dates differ... */
- y = (ndate(a->odate) < ndate(b->odate)) ? -1 : 1;
- /* ...that settles it... */
- } else {
- if(ntime(a->otime) == ntime(b->otime)) y = 0;
- else y = (ntime(a->otime) < ntime(b->otime)) ? -1 : 1;
- /* ...else compare times */
- }
- return((rev) ? y : -y);
- } else {
- y = strcmpi(a->oname, b->oname);
- /* Name comparison */
- return((rev) ? -y : y);
- }
- }
-
-
- /*
- * Print a list of names in 1 or 5 columns. Special action is needed for
- * HPFS names, which may straddle columns.
- *
- */
-
- static void shortlist(int k)
- { int i;
- int count = 0;
- int width;
- CHAR ch;
- char *name;
-
- for(i = 0; i < k; i++) {
- name = obuf[i].oname;
- if(obuf[i].oattr & FILE_DIRECTORY)
- (void) strcat(name, "\\");
- /* Mark directories */
- if(fs == FS_FAT) {
- (void) strlwr(name);
- width = 15;
- } else {
- width = strlen(name);
- if(width < 13) width = 13;
- width = (width+16)/15*15;
- if(width+count > SCRWID) {
- ch = endlin();
- fputc(ch, stdout);
- count = 0;
- }
- }
-
- /* Print the name and padding */
-
- fprintf(stdout, "%-*s", col1 ? strlen(name) : width, name);
- count += width;
- if(count >= SCRWID || col1) {
- ch = endlin();
- fputc(ch, stdout);
- count = 0;
- }
- }
- if(count) { /* Finish incomplete line */
- ch = endlin();
- fputc(ch, stdout);
- }
- }
-
-
- /*
- * End a line and watch for screen overflow
- *
- */
-
- static CHAR endlin()
- { int c;
-
- if(tsc && ++lc >= SCRSIZ) { /* Pause if output is to console screen */
- /* and we've shown a screenful */
- fputs("\n--More--", stdout);
- (void) fflush(stdout);
- c = getch();
- fputs("\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b", stdout);
-
- switch(c) {
- case '\r': /* <RETURN> - show 1 more line */
- lc = SCRSIZ - 1;
- break;
-
- case 'q': /* Quit with "q" or "ctrl-C" */
- case 'Q':
- case '\003':
- exit(EXIT_FAILURE);
-
- default: /* else show another screenful */
- lc = 0;
- break;
- }
- return('\b');
- } else return('\n');
- }
-
-
- /*
- * List everything about files
- *
- */
-
- static void longlist(int k) /* k is total number to list */
- { int i;
- int cdate;
- CHAR ch;
- char *mon;
- struct llst l;
-
- cdate = gcdate(); /* Get current date (in months) */
-
- for(i = 0; i < k; i++) {
- fill(i, &l); /* Fill llst structure */
- fprintf(stdout, "%s%9ld %2d %s ", l.fattr, l.size, l.day,
- mname(l.mnum));
- if(cdate >= (l.yr * 12 +l.mnum) + 12) {
- fprintf(stdout, " %4d ", l.yr);
- /* Print year if too old */
- } else {
- fprintf(stdout, "%2d:%02d%c ", l.hh, l.mm, l.ap);
- /* else print time */
- }
- if(fs == FS_FAT) (void) strlwr(obuf[i].oname);
- fprintf(stdout, obuf[i].oname);
- ch = endlin();
- fputc(ch, stdout);
- }
- }
-
-
- /*
- * Fill long list structure with file information
- *
- */
-
- static void fill(int i, struct llst *ll)
- { if(obuf[i].oattr & FILE_DIRECTORY) {
- ll->size = eas ? obuf[i].easize : 0;
- } else {
- ll->size = eas ? obuf[i].easize :
- usage ? obuf[i].oasize :
- obuf[i].osize;
- }
-
- (void) strcpy(ll->fattr, "------");
- if(obuf[i].oattr & FILE_DIRECTORY) ll->fattr[0] = 'd';
- if(obuf[i].easize != 0) ll->fattr[1] = 'e';
- if(obuf[i].oattr & FILE_ARCHIVED) ll->fattr[2] = 'a';
- if(obuf[i].oattr & FILE_SYSTEM) ll->fattr[3] = 's';
- if(obuf[i].oattr & FILE_HIDDEN) ll->fattr[4] = 'h';
- if(obuf[i].oattr & FILE_READONLY) ll->fattr[5] = 'r';
-
- ll->day = obuf[i].odate.day;
- ll->mnum = obuf[i].odate.month;
- ll->yr = obuf[i].odate.year + 1980;
- ll->hh = obuf[i].otime.hours;
- ll->mm = obuf[i].otime.minutes;
- ll->ap = ll->hh >= 12 ? 'p' : 'a';
- if(ll->hh > 12) ll->hh -= 12;
- if(ll->hh == 0) ll->hh = 12;
- }
-
-
- /*
- * Get current date (in months) for comparison
- *
- */
-
- static int gcdate()
- { DATETIME dt;
-
- (void) DosGetDateTime(&dt);
-
- return(dt.year*12 + dt.month);
- }
-
-
- /*
- * Convert month number to month name
- *
- */
-
- static char *mname(int n)
- { struct tm t;
- static char res[4];
-
- if(n <= 0 || n > 12) return("???");
-
- t.tm_mon = --n;
- (void) strftime(res, 3, "%b", &t);
-
- return(res);
- }
-
-
- /*
- * Function to determine the type of file system on the drive specified
- * in 'path'.
- *
- * Returns FS_FAT or FS_HPFS; any error causes the result to default to
- * FS_FAT.
- *
- */
-
- static enum fs_t fstype(CHAR *path)
- { USHORT res;
- UCHAR fsqbuf[FSQBUFSIZE];
- UCHAR *p;
- USHORT fsqbuflen = FSQBUFSIZE;
- UCHAR drive[3];
-
- if(path[1] != ':') { /* No drive in path - use default */
- curdrv(drive);
- } else {
- drive[0] = path[0];
- drive[1] = path[1];
- drive[2] = '\0';
- }
-
- if(DosQFSAttach(drive, 0, FSAIL_QUERYNAME, fsqbuf, &fsqbuflen, 0L) != 0)
- return(FS_FAT);
-
- /* Set 'p' to point to the file system name */
-
- p = fsqbuf + sizeof(USHORT); /* Point past device type */
- p += (USHORT) *p + 2*sizeof(USHORT) + 1;
- /* Point past drive name and FS name */
- /* length */
-
- if(strcmp(p, "HPFS") == 0) return(FS_HPFS);
-
- return(FS_FAT);
- }
-
- /*
- * Function to indicate if a given file descriptor relates to the screen
- * or keyboard. This replaces the MSC 6.0 version, which just says if the
- * file descriptor describes any device.
- *
- */
-
- static BOOL my_isatty(int fd)
- { USHORT rc;
- USHORT HandType; /* Handle type (returned) */
- USHORT FlagWord; /* Device driver attribute (returned) */
-
- rc = DosQHandType((HFILE) fd, &HandType, &FlagWord);
- if(rc != 0) return(FALSE); /* Error */
-
- if((HandType & 0xff) != 1) return(FALSE);
- /* Not character device */
-
- if((FlagWord & 0x03) != 0) return(TRUE);
- /* Standard input or output */
- return(FALSE);
- }
-
-
- /*
- * Function to output program usage information
- *
- */
-
- static void putusage(void)
- { char **p = (char **) helpinfo;
- char *q;
-
- for(;;) {
- q = *p++;
- if(*q == '\0') break;
-
- fprintf(stderr, q, progname);
- fputc('\n', stderr);
- }
- fprintf(stderr, "\nThis is version %d.%d\n", VERSION, EDIT);
- }
-
- /*
- * End of file: ls.c
- *
- */